#include "interrupt.h"
#include "pmm.h"
#include "printf.h"
#include "panic.h"
#include "plic.h"
#include "clint.h"
#include "riscv.h"
#include "vmm.h"

// 声明汇编实现的中断入口函数
extern void trap_entry(void);

// 全局中断向量表实例
irq_descriptor_t irq_vector_table[MAX_IRQ_NUM] = {0};

// 异常计数器
static volatile int exception_count = 0;

/**
 * 初始化中断系统核心函数
 */
void trap_init(void) {
    // 1. 初始化中断向量表
    for (int i = 0; i < MAX_IRQ_NUM; i++) {
        irq_vector_table[i].handler_count = 0;
        irq_vector_table[i].priority = IRQ_PRIORITY_0;
        irq_vector_table[i].enabled = 0;
        for (int j = 0; j < MAX_HANDLERS_PER_IRQ; j++) {
            irq_vector_table[i].handlers[j] = NULL;
        }
    }

    // 2. 配置中断入口
    uint64_t trap_entry_addr = (uint64_t)trap_entry;
    w_mtvec(trap_entry_addr | MTVEC_DIRECT);

    // 3. 初始化硬件中断控制器
    plic_init();
    clint_init();

    // 4. 使能M模式全局中断
    w_mstatus(r_mstatus() | MSTATUS_MIE);

    // 5. 使能M模式外部中断和时钟中断
    w_mie(r_mie() | MIE_MEIE | MIE_MTIE);

    printf("中断系统初始化完成（支持时钟和外部设备中断）\n");
}

/**
 * 注册中断处理函数
 */
int register_interrupt(irq_num_t irq, interrupt_handler_t h, irq_priority_t prio) {
    if (irq >= MAX_IRQ_NUM || h == NULL || prio > IRQ_PRIORITY_7) {
        printf("注册中断失败：无效参数（irq=%d, prio=%d）\n", irq, prio);
        return -1;
    }

    irq_descriptor_t *desc = &irq_vector_table[irq];
    if (desc->handler_count >= MAX_HANDLERS_PER_IRQ) {
        printf("注册中断失败：IRQ%d处理函数数量已满（最大%d个）\n", irq, MAX_HANDLERS_PER_IRQ);
        return -1;
    }

    desc->handlers[desc->handler_count++] = h;
    if (prio > desc->priority) {
        desc->priority = prio;
        plic_set_priority(irq, prio);
    }

    printf("注册中断成功：IRQ%d（优先级%d，当前处理函数数：%d）\n", 
           irq, prio, desc->handler_count);
    return 0;
}

/**
 * 注销中断处理函数
 */
int unregister_interrupt(irq_num_t irq, interrupt_handler_t h) {
    if (irq >= MAX_IRQ_NUM || h == NULL) {
        return -1;
    }

    irq_descriptor_t *desc = &irq_vector_table[irq];
    for (int i = 0; i < desc->handler_count; i++) {
        if (desc->handlers[i] == h) {
            desc->handlers[i] = desc->handlers[desc->handler_count - 1];
            desc->handlers[desc->handler_count - 1] = NULL;
            desc->handler_count--;
            printf("注销中断成功：IRQ%d（剩余处理函数数：%d）\n", irq, desc->handler_count);
            return 0;
        }
    }

    printf("注销中断失败：IRQ%d未找到处理函数\n", irq);
    return -1;
}

/**
 * 使能特定中断
 */
void enable_interrupt(irq_num_t irq) {
    if (irq >= MAX_IRQ_NUM) {
        printf("使能中断失败：无效IRQ%d\n", irq);
        return;
    }

    irq_descriptor_t *desc = &irq_vector_table[irq];
    if (desc->enabled) {
        return;
    }

    desc->enabled = 1;
    if (irq == IRQ_TIMER) {
        w_mie(r_mie() | MIE_MTIE);
    } else {
        plic_enable(irq, r_mhartid());
    }
    printf("使能中断：IRQ%d\n", irq);
}

/**
 * 禁用特定中断
 */
void disable_interrupt(irq_num_t irq) {
    if (irq >= MAX_IRQ_NUM) {
        printf("禁用中断失败：无效IRQ%d\n", irq);
        return;
    }

    irq_descriptor_t *desc = &irq_vector_table[irq];
    if (!desc->enabled) {
        return;
    }

    desc->enabled = 0;
    if (irq == IRQ_TIMER) {
        w_mie(r_mie() & ~MIE_MTIE);
    } else {
        plic_disable(irq, r_mhartid());
    }
    printf("禁用中断：IRQ%d\n", irq);
}

/**
 * 解析异常原因并打印详细信息
 * 修改: 不终止系统,仅打印警告信息
 */
static void handle_exception(uint64_t cause, uint64_t epc) {
    exception_count++;
    
    printf("\n===== 异常详情 (第%d次,已跳过) =====\n", exception_count);
    
    // 简化打印,避免对齐问题
    printf("异常原因代码: 0x%x\n", (uint32_t)cause);
    printf("异常发生地址: 0x%x\n", (uint32_t)epc);
    
    // 解析异常类型
    switch (cause) {
        case 0:  printf("异常类型: 指令地址未对齐\n"); break;
        case 1:  printf("异常类型: 指令访问故障\n"); break;
        case 2:  printf("异常类型: 非法指令\n"); break;
        case 5:  printf("异常类型: 加载地址未对齐\n"); break;
        case 6:  printf("异常类型: 加载访问故障\n"); break;
        case 7:  printf("异常类型: 存储/AMO地址未对齐\n"); break;
        case 8:  printf("异常类型: 存储/AMO访问故障\n"); break;
        case 12: printf("异常类型: 指令页错误\n"); break;
        case 13: printf("异常类型: 加载页错误\n"); break;
        case 15: printf("异常类型: 存储/AMO页错误\n"); break;
        default: printf("异常类型: 未知\n");
    }
    
    printf("==== 跳过异常,继续执行 ====\n\n");
}

/**
 * 中断/异常处理核心逻辑
 * 修改: 异常发生时不调用panic,跳过异常指令继续执行
 */
void trap_handler(uint64_t cause, uint64_t epc) {
    uint64_t saved_mstatus = r_mstatus();
    
    // 处理异常(不终止系统)
    if ((cause & (1ULL << 63)) == 0) {
        // 打印异常信息
        handle_exception(cause, epc);
        
        // 跳过引发异常的指令(假设是4字节指令)
        w_mepc(epc + 4);
        
        // 恢复中断状态并返回
        w_mstatus(saved_mstatus | MSTATUS_MIE);
        return;  // 不调用panic,直接返回
    }

    // 处理中断
    uint64_t irq = cause & ~(1ULL << 63);
    irq_descriptor_t *desc = NULL;
    uint32_t plic_irq = 0;

    switch (irq) {
        case 7:  // M模式时钟中断
            desc = &irq_vector_table[IRQ_TIMER];
            break;
        
        case 11: // M模式外部中断
            plic_irq = plic_claim(r_mhartid());
            if (plic_irq == 0) {
                printf("警告: PLIC无待处理中断\n");
                w_mstatus(saved_mstatus | MSTATUS_MIE);
                return;
            }
            if (plic_irq + 1 < MAX_IRQ_NUM) {
                desc = &irq_vector_table[plic_irq + 1];
            } else {
                printf("警告: PLIC中断号%d超出范围\n", plic_irq);
                plic_complete(r_mhartid(), plic_irq);
                w_mstatus(saved_mstatus | MSTATUS_MIE);
                return;
            }
            break;
        
        default:
            printf("未知中断: irq=%d\n", (int)irq);
            w_mstatus(saved_mstatus | MSTATUS_MIE);
            return;
    }

    // 执行中断处理函数
    if (desc && desc->enabled) {
        uint32_t current_prio = desc->priority;
        plic_set_threshold(r_mhartid(), current_prio);

        for (int i = 0; i < desc->handler_count; i++) {
            if (desc->handlers[i]) {
                desc->handlers[i]();
            }
        }

        plic_set_threshold(r_mhartid(), 0);
    }

    // 完成PLIC中断
    if (irq == 11) {
        plic_complete(r_mhartid(), plic_irq);
    }
    
    // 恢复中断状态
    w_mstatus(saved_mstatus | MSTATUS_MIE);
}

